// Aaron and Jason curtis, incorporating code from 
// www.hacktronics.com LCD thermostat project

#include <OneWireTemp.h>
#include <LiquidCrystal.h>
#include <ByteBuffer.h>

// Connections:
// rs (LCD pin 4) to Arduino pin 12
// rw (LCD pin 5) to Arduino pin 11
// enable (LCD pin 6) to Arduino pin 10
// LCD pin 15 to Arduino pin 13
// LCD pins d4, d5, d6, d7 to Arduino pins 5, 4, 3, 2
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
int compressor = 5;
int heater = 4;
int plus_or_minus = 2;
int target_temp = 62;
int upper_temp, lower_temp;
int knob_raw = 0;
int relCycCnt = 1;
boolean heatOn;
boolean compOn;

ByteBuffer buffer;

//one-wire temp sensors for fridge and freezer on pins 1 and 2
OWTemp frj(2); 
OWTemp frz(3);

//custom icons for the LCD display:
byte fzIcon[8] = {
  B11100,
  B10000,
  B11000,
  B10000,
  B10111,
  B00001,
  B00010,
  B00111
};
#define FZICON 0
byte fjIcon[8] = {
  B11100,
  B10000,
  B11000,
  B10001,
  B10001,
  B00001,
  B01001,
  B00110
};
#define FJICON 1
byte cmpIcon[8] = {
  B00000,
  B00000,
  B00111,
  B01011,
  B11101,
  B10110,
  B11100,
  B00000
};
#define CMPICON 2
byte fireIcon[8] = {
  B00010,
  B00110,
  B01010,
  B10001,
  B10101,
  B10101,
  B01011,
  B01110
};
#define FIREICON 3
byte rangeIcon[8] = {
  B00000,
  B00000,
  B00000,
  B01010,
  B10001,
  B01010,
  B00000,
  B00000
};
#define RANGEICON 4
byte arrowIcon[8] = {
  B01000,
  B01000,
  B10000,
  B10100,
  B10010,
  B01111,
  B00010,
  B00100
};
#define ARROWICON 5


void setup(void) {
  
  // Initialize the buffer with a capacity for 256 bytes
  buffer.init(256);
  
  pinMode(compressor, OUTPUT);
  pinMode(heater, OUTPUT);
  Serial.begin(9600);
  lcd.begin(16,2);         // rows, columns.  use 2,16 for a 2x16 LCD, etc.
  lcd.noAutoscroll();
  lcd.clear();                  // start with a blank screen
  lcd.setCursor(0,0);           // set cursor to column 0, row 0
  
  //custom icons for LCD
  lcd.createChar(FZICON, fzIcon); //freezer
  lcd.createChar(FJICON, fjIcon); //fridge
  lcd.createChar(CMPICON, cmpIcon); //compressor
  lcd.createChar(FIREICON, fireIcon); //heater
  lcd.createChar(RANGEICON, rangeIcon); //range (like "<>")
  lcd.createChar(ARROWICON, arrowIcon); //arrow that goes down and right

  startSensor(&frj);
  //startSensor(&frz);
}

void startSensor(OWTemp * sensor){
  if ( !sensor->search(sensor->addr)) {
      lcd.clear(); lcd.print("No more addrs");
      delay(1000);
      sensor->reset_search();
      return;
  }

  if ( sensor->crc8( sensor->addr, 7) != sensor->addr[7]) {
      lcd.clear(); lcd.print("CRC not valid!");
      delay(1000);
      return;
  }
}

void doRelays(void) {
    if (frj.FWhole>upper_temp) {
      digitalWrite(compressor, HIGH);
    }
    if (frj.FWhole<target_temp) {
      digitalWrite(compressor, LOW);
    }
    if (frj.FWhole>target_temp) {
      digitalWrite(heater, LOW);
    }
    if (frj.FWhole<lower_temp) {
      digitalWrite(heater, HIGH);
    }
}

void printTemp(void) {

  Serial.print("fridge temp(C): ");
  Serial.println(frj.Tc_100/100);
  Serial.print("freezer temp(C): ");
  Serial.println(frz.Tc_100/100);
  compOn=digitalRead(compressor)==HIGH;
  heatOn=digitalRead(heater)==HIGH;
  if (compOn)  {
    Serial.println("compressor on");
  }
  if (heatOn)  {
    Serial.println("heater on");
  }
  //new LCD format:
  // 0123456789012345
  //0Jxx.xCyyF|xxoyyF
  //1Z-zz.xxCzzF  >H
  //
  //J is FRJICON,o is the <> icon, Z is the FRZICON, and > is the down-right arrow.
  
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.write(FJICON);
  if (frj.SignBit) {
    //WARNING: sign bit will cause LCD overflow :(
    lcd.print("-");
  }
  lcd.print( ((int)frj.Tc_100/10)/10);
  lcd.print("C");
  lcd.print(frj.FWhole);
  lcd.print("F|");
  lcd.print(lower_temp);
  lcd.write(RANGEICON);
  lcd.print(upper_temp);
  lcd.print("F");
  
  // second line:
  lcd.setCursor(0,1); 
  lcd.write(FZICON);
  if (frz.SignBit) {  
     lcd.print("-");
  }
  lcd.print(frz.Tc_100/100);
  lcd.print("C");
  lcd.print(frz.FWhole);
  lcd.print("F  ");
  if(compOn | heatOn){
    lcd.write(ARROWICON);
  }
  if(compOn){
    lcd.write(CMPICON);    
  }
  else if(heatOn){
    lcd.write(FIREICON);    
  }  
}

void writeEEPROM(void){
  buffer.putFloat(frj.Tc_100);
}

void loop(void) {
  knob_raw=analogRead(0);
  target_temp=map(knob_raw, 0, 1023, 30, 100);
  lower_temp=target_temp-plus_or_minus;
  upper_temp=target_temp+plus_or_minus;
  frj.getTemp();
  //frz.getTemp();
  
  if (relCycCnt == 10){// only change relays every 10 secs
    relCycCnt = 1;
    doRelays();
  }
//  writeEEPROM();
  relCycCnt+=1;
  printTemp();
  delay(1000);
}
